package org.xmx0632.connector.cfg;

import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.annotation.PropertySources;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.xmx0632.connector.initalizer.AesProtocolInitalizer;
import org.xmx0632.connector.initalizer.SslProtocolInitalizer;
import org.xmx0632.connector.initalizer.TcpProtocolInitalizer;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;

@ComponentScan("org.xmx0632.connector")
@Configuration
@ImportResource("classpath:spring/applicationContext.xml")

/**
 * 
 * 1.查找classpath:config.properties,如果没有则报错
 * 2.查找/opt/wsn/conf/connector/config.properties,如果有则使用该文件的值覆盖已有值
 * 3.查找d:/wsn/conf/connector/config.properties,如果有则使用该文件的值覆盖已有值
 * 
 */
@PropertySources({ @PropertySource(value = "classpath:config.properties", ignoreResourceNotFound = false),
		@PropertySource(value = "file:/opt/wsn/conf/connector/config.properties", ignoreResourceNotFound = true),
		@PropertySource(value = "file:///d:/wsn/conf/connector/config.properties", ignoreResourceNotFound = true) })
public class SpringConfig {

	@Value("${tcp.boss.thread.count}")
	private int tcpBossCount;

	@Value("${tcp.worker.thread.count}")
	private int tcpWorkerCount;

	@Value("${ssl.boss.thread.count}")
	private int sslBossCount;

	@Value("${ssl.worker.thread.count}")
	private int sslWorkerCount;

	@Value("${aes.boss.thread.count}")
	private int aesBossCount;

	@Value("${aes.worker.thread.count}")
	private int aesWorkerCount;

	@Value("${tcp.port}")
	private int tcpPort;

	@Value("${ssl.port}")
	private int sslPort;

	@Value("${aes.port}")
	private int aesPort;

	@Value("${so.keepalive}")
	private boolean keepAlive;

	@Value("${so.backlog}")
	private int backlog;

	@Value("${log4j.configuration}")
	private String log4jConfiguration;

	@Value("${mq.brokerURL}")
	private String mqBrokerURL;

	@Autowired
	private TcpProtocolInitalizer tcpProtocolInitalizer;

	@Autowired
	private AesProtocolInitalizer aesProtocolInitalizer;

	@Autowired
	private SslProtocolInitalizer sslProtocolInitalizer;

	@SuppressWarnings("unchecked")
	@Bean(name = "tcpServerBootstrap")
	public ServerBootstrap tcpBootstrap() {
		ServerBootstrap b = new ServerBootstrap();
		b.group(tcpBossGroup(), tcpWorkerGroup()).channel(NioServerSocketChannel.class)
				.childHandler(tcpProtocolInitalizer);
		Map<ChannelOption<?>, Object> tcpChannelOptions = tcpChannelOptions();
		Set<ChannelOption<?>> keySet = tcpChannelOptions.keySet();
		for (@SuppressWarnings("rawtypes")
		ChannelOption option : keySet) {
			b.option(option, tcpChannelOptions.get(option));
		}
		return b;
	}

	@SuppressWarnings("unchecked")
	@Bean(name = "sslServerBootstrap")
	public ServerBootstrap sslBootstrap() {
		ServerBootstrap b = new ServerBootstrap();
		b.group(sslBossGroup(), sslWorkerGroup()).channel(NioServerSocketChannel.class)
				.childHandler(sslProtocolInitalizer);
		Map<ChannelOption<?>, Object> sslChannelOptions = sslChannelOptions();
		Set<ChannelOption<?>> keySet = sslChannelOptions.keySet();
		for (@SuppressWarnings("rawtypes")
		ChannelOption option : keySet) {
			b.option(option, sslChannelOptions.get(option));
		}
		return b;
	}

	@SuppressWarnings("unchecked")
	@Bean(name = "aesServerBootstrap")
	public ServerBootstrap aesBootstrap() {
		ServerBootstrap b = new ServerBootstrap();
		b.group(aesBossGroup(), aesWorkerGroup()).channel(NioServerSocketChannel.class)
				.childHandler(aesProtocolInitalizer);
		Map<ChannelOption<?>, Object> aesChannelOptions = aesChannelOptions();
		Set<ChannelOption<?>> keySet = aesChannelOptions.keySet();
		for (@SuppressWarnings("rawtypes")
		ChannelOption option : keySet) {
			b.option(option, aesChannelOptions.get(option));
		}
		return b;
	}

	@Bean(name = "tcpBossGroup", destroyMethod = "shutdownGracefully")
	public NioEventLoopGroup tcpBossGroup() {
		return new NioEventLoopGroup(tcpBossCount);
	}

	@Bean(name = "tcpWorkerGroup", destroyMethod = "shutdownGracefully")
	public NioEventLoopGroup tcpWorkerGroup() {
		return new NioEventLoopGroup(tcpWorkerCount);
	}

	@Bean(name = "sslBossGroup", destroyMethod = "shutdownGracefully")
	public NioEventLoopGroup sslBossGroup() {
		return new NioEventLoopGroup(sslBossCount);
	}

	@Bean(name = "sslWorkerGroup", destroyMethod = "shutdownGracefully")
	public NioEventLoopGroup sslWorkerGroup() {
		return new NioEventLoopGroup(sslWorkerCount);
	}

	@Bean(name = "aesTcpBossGroup", destroyMethod = "shutdownGracefully")
	public NioEventLoopGroup aesBossGroup() {
		return new NioEventLoopGroup(aesBossCount);
	}

	@Bean(name = "aesWorkerGroup", destroyMethod = "shutdownGracefully")
	public NioEventLoopGroup aesWorkerGroup() {
		return new NioEventLoopGroup(aesWorkerCount);
	}

	@Bean(name = "tcpSocketAddress")
	public InetSocketAddress tcpPort() {
		return new InetSocketAddress(tcpPort);
	}

	@Bean(name = "sslSocketAddress")
	public InetSocketAddress sslPort() {
		return new InetSocketAddress(sslPort);
	}

	@Bean(name = "aesSocketAddress")
	public InetSocketAddress aesPort() {
		return new InetSocketAddress(aesPort);
	}

	public Map<ChannelOption<?>, Object> tcpChannelOptions() {
		Map<ChannelOption<?>, Object> options = new HashMap<ChannelOption<?>, Object>();
		options.put(ChannelOption.SO_KEEPALIVE, keepAlive);
		options.put(ChannelOption.SO_BACKLOG, backlog);
		return options;
	}

	public Map<ChannelOption<?>, Object> sslChannelOptions() {
		Map<ChannelOption<?>, Object> options = new HashMap<ChannelOption<?>, Object>();
		options.put(ChannelOption.SO_KEEPALIVE, keepAlive);
		options.put(ChannelOption.SO_BACKLOG, backlog);
		return options;
	}

	public Map<ChannelOption<?>, Object> aesChannelOptions() {
		Map<ChannelOption<?>, Object> options = new HashMap<ChannelOption<?>, Object>();
		options.put(ChannelOption.SO_KEEPALIVE, keepAlive);
		options.put(ChannelOption.SO_BACKLOG, backlog);
		return options;
	}

	@Bean(name = "stringEncoder")
	public StringEncoder stringEncoder() {
		return new StringEncoder();
	}

	@Bean(name = "stringDecoder")
	public StringDecoder stringDecoder() {
		return new StringDecoder();
	}

	/**
	 * Necessary to make the Value annotations work.
	 * 
	 * @return
	 */
	@Bean
	public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
		return new PropertySourcesPlaceholderConfigurer();
	}

}
